package jenkins.plugins.publish_over_ssh.onepublish;

import hudson.model.BuildListener;
import jenkins.plugins.publish_over_ssh.BapSshClient;
import jenkins.plugins.publish_over_ssh.BapSshTransfer;
import net.sf.json.JSONArray;
import net.sf.json.JSONException;
import net.sf.json.JSONObject;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.LinkedBlockingQueue;

public class UpdateUtil extends Thread {
	final LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>();
	private Map<String, String> localremoteMd5;
	private List<String> ignores=new ArrayList<>();
	private BapSshTransfer transf;
	private BuildListener listener;
	private BapSshClient client;
	private String serverName;
	private StringBuffer strbufer=new StringBuffer();

	public void setTransf(BapSshTransfer transf) {
		this.transf = transf;
	}

	public void setListener(BuildListener listener) {
		this.listener = listener;
	}

	public void setClient(BapSshClient client) {
		this.client = client;
	}

	public void setServerName(String serverName) {
		this.serverName = serverName;
	}

	@Override
	public void run() {
		try {
			this.setLog("");
			this.setLog("开始更新>>>>>"+serverName+"===="+transf.getRemoteDirectory());
			startRecursion();
			this.printLog();
		} catch (Exception e) {
			this.printLog();
			e.printStackTrace();
			listener.getLogger().println(e);
		}
	}

	public boolean checkIsIgnore(String filePath) throws Exception{
		boolean flag=false;
		for(String ignore:ignores){
			if(filePath.startsWith(ignore)){
				flag=true;
				break;
			}
		}
		return flag;
	}
	/* 
	 *  递归更新
	 *  */
	 
	public void startRecursion() throws Exception{
		File root = new File(transf.getSourceFiles());
		if(root.isFile()){
			this.setLog("物理路径不正确，请检查");
			return;
		}
		if(!root.exists()){
			this.setLog("物理路径不存在，请检查");
			return;
		}
		JSONObject json = new JSONObject();
		JSONArray beforeJson=new JSONArray();
		JSONArray afterJson=new JSONArray();
		JSONArray ignoresJson=new JSONArray();
		try{
			if(transf.getExecCommand()!=null&&transf.getExecCommand().length()>0){
				json = JSONObject.fromObject(transf.getExecCommand());
			}
		}catch (JSONException e){
			e.printStackTrace();
			this.setLog("命令错误：\n"+transf.getExecCommand());
			this.setLog("停止更新");
			return;
		}
		try{
			beforeJson=json.getJSONArray("before");
		}catch (JSONException e){
		}
		try{
			afterJson=json.getJSONArray("after");
		}catch (JSONException e){
		}
		try{
			ignoresJson=json.getJSONArray("ignores");
		}catch (JSONException e){
		}
		for(int i=0;i<beforeJson.size();i++){
			client.exceCmd(beforeJson.get(i).toString());
		}
		ignores=JSONArray.toList(ignoresJson,String.class);
		int osType = 0;
		if (System.getProperty("os.name").startsWith("Windows")) {
			osType = 0;// window
		} else {
			osType = 1;// linux
		}
		if(osType==0){
			localremoteMd5 = new HashMap<String, String>();
			getLocalFileMap(root);
		}else{
			localremoteMd5 =Md5Util.getMd5Inlinux(root.getAbsolutePath());
		}
		Map<String, String> remoteMd5 = client.getRemoteMd5(transf.getRemoteDirectory());
		for (Map.Entry<String, String> remotemd5 : remoteMd5.entrySet()) {
			if(ignores!=null&&ignores.size()!=0&&checkIsIgnore(remotemd5.getKey())){
				continue;
			}
			String localFilePath = "";
			if (osType == 0) {
				localFilePath = remotemd5.getKey().replace(transf.getRemoteDirectory(), transf.getSourceFiles()).replace("/","\\");
			} else {
				localFilePath = remotemd5.getKey().replace(transf.getRemoteDirectory(), transf.getSourceFiles());
			}
			/*File file = new File(localFilePath);*/
			// 判断文件是否存在
			if (!localremoteMd5.containsKey(localFilePath)) {
				String temp=remotemd5.getKey();
				if(temp.contains("$")){
					temp=temp.replace("$","\\$");
				}
				client.exceCmd("rm -rf " + temp);
				this.setLog("删除:" + remotemd5.getKey());
			}
		}
		for (Map.Entry<String, String> localmd5 : localremoteMd5.entrySet()) {
			if(ignores!=null&&ignores.size()!=0&&checkIsIgnore(localmd5.getKey())){
				continue;
			}
			String remoteFilePath = "";
			String remoteFileDir = "";
			if (osType == 0) {
				remoteFilePath = localmd5.getKey().replace(transf.getSourceFiles(), transf.getRemoteDirectory()).replace("\\","/");
				remoteFileDir = new File(remoteFilePath).getParent().replace("\\", "/") + "/";
			} else {
				remoteFilePath = localmd5.getKey().replace(transf.getSourceFiles(), transf.getRemoteDirectory());
				remoteFileDir = new File(remoteFilePath).getParent() + "/";
			}
			if (!remoteMd5.keySet().contains(remoteFilePath)) {
				client.exceCmd("mkdir -p " + remoteFileDir);
				client.SFTPFile(localmd5.getKey(), remoteFileDir);
				this.setLog("新增:" + localmd5.getKey());
			} else {
				if (!localmd5.getValue().equals(remoteMd5.get(remoteFilePath))) {
					client.SFTPFile(localmd5.getKey(), remoteFileDir);
					this.setLog("更新:" + localmd5.getKey());
				}
			}
		}
		String shellPah=(new File("")).getAbsolutePath().replace("bin","webapps/ROOT/WEB-INF")+"/delDir.sh";
		ClassLoader classLoader = getClass().getClassLoader();
		client.exceCmd("cd "+transf.getRemoteDirectory());
		File shellcode=new File(shellPah);
		client.SFTPFile(shellcode.getAbsolutePath(),transf.getRemoteDirectory());
		client.exceCmd("chmod 755 "+transf.getRemoteDirectory()+"/delDir.sh");
		client.exceCmd("cd "+transf.getRemoteDirectory()+";sh "+transf.getRemoteDirectory()+"/delDir.sh");
		client.exceCmd("rm -rf "+transf.getRemoteDirectory()+"/delDir.sh");
		for(int i=0;i<afterJson.size();i++){
			client.exceCmd(afterJson.get(i).toString());
		}
		client.disconnectQuietly();
		this.setLog("更新完成>>>>>"+serverName+"===="+transf.getRemoteDirectory());
	}
	
	public void getLocalFileMap(File dir) throws Exception{
		File[] fs = dir.listFiles();
		for (int i = 0; i < fs.length; i++) {
			if (fs[i].isDirectory()) {
				try {
					getLocalFileMap(fs[i]);
				} catch (Exception e) {
					e.printStackTrace();
				}
			} else {
				String filePath = fs[i].getAbsolutePath();
				String fileMd5 = Md5Util.getMD5(fs[i]);
				localremoteMd5.put(filePath, fileMd5);
			}
		}
	}

	public void printLog() {
		listener.getLogger().print(strbufer.toString());
	}
	public void setLog(String log) {
		strbufer.append(log+"\n");
	}
}
